﻿using SymulatorEthernetWPF.Shared;
using SymulatorEthernetWPF.SimObjects.Layers.DataLink;
using SymulatorEthernetWPF.SimObjects.Layers.Physical;
using SymulatorEthernetWPF.UserInterface;
using SymulatorEthernetWPF.UserInterface.UIElements;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace SymulatorEthernetWPF.SimObjects.Devices
{
    /// <summary>
    /// Interaction logic for DeviceControl.xaml
    /// </summary>
    /// 
    [Serializable]
    public abstract partial class DeviceControl : UserControl, ISerializable
    {
        public Guid GUID;
        private bool _hasMoved;
        private Point _initialDraggingPosition = new Point(0, 0);
        private bool _isInitialpositioning = true;
        private bool _isMoving = true;

        public byte[] RawImageData;
        private bool _selected;
        public ObservableCollection<TaskQueueItem> taskQueue = new ObservableCollection<TaskQueueItem>();
        private bool _tmp = true;

        public ObservableCollection<ReceivedData> receivedData = new ObservableCollection<ReceivedData>();

        private NetworkInterface _networkInterface1;
        private NetworkInterface _networkInterface2;
        private NetworkInterface _networkInterface3;
        private NetworkInterface _networkInterface4;
        private NetworkInterface _networkInterface5;
        private NetworkInterface _networkInterface6;
        private NetworkInterface _networkInterface7;
        private NetworkInterface _networkInterface8;

        public ObservableCollection<String> logList = new ObservableCollection<string>();

        internal SwitchTable switchTable = new SwitchTable();

        public List<NetworkInterface> interfaces = new List<NetworkInterface>();
        

        public DeviceControl()
        {
            InitializeComponent();
            GUID = Guid.NewGuid();
            switchTable = new SwitchTable();
            NetworkInterface1 = new NetworkInterface(networkInterface1Handler);
            NetworkInterface2 = new NetworkInterface(networkInterface2Handler);
            NetworkInterface3 = new NetworkInterface(networkInterface3Handler);
            NetworkInterface4 = new NetworkInterface(networkInterface4Handler);
            NetworkInterface5 = new NetworkInterface(networkInterface5Handler);
            NetworkInterface6 = new NetworkInterface(networkInterface6Handler);
            NetworkInterface7 = new NetworkInterface(networkInterface7Handler);
            NetworkInterface8 = new NetworkInterface(networkInterface8Handler);

            interfaces.Add(NetworkInterface1);
            interfaces.Add(NetworkInterface2);
            interfaces.Add(NetworkInterface3);
            interfaces.Add(NetworkInterface4);
            interfaces.Add(NetworkInterface5);
            interfaces.Add(NetworkInterface6);
            interfaces.Add(NetworkInterface7);
            interfaces.Add(NetworkInterface8);

            _initialDraggingPosition.X = 48;
            _initialDraggingPosition.Y = 42;

            NetworkInterface1.Name = "eth0";
            NetworkInterface2.Name = "eth1";
            NetworkInterface3.Name = "eth2";
            NetworkInterface4.Name = "eth3";
            NetworkInterface5.Name = "eth4";
            NetworkInterface6.Name = "eth5";
            NetworkInterface7.Name = "eth6";
            NetworkInterface8.Name = "eth7";

            Opacity = 0;

            StaticVars.MainWindow.scrollViewer.MouseMove += new MouseEventHandler(updatePosition);
        }

        public String getDeviceType()
        {
            if(this.GetType()==typeof(HostControl))
            {
                return "Host";
            }
            else if (this.GetType() == typeof(HubControl))
            {
                return "Hub";
            }
            else if (this.GetType() == typeof(SwitchControl))
            {
                return "Switch";
            }
            return "Unknown";
        }
        
        void updatePosition(object sender, MouseEventArgs e)
        {
            if (_isMoving)
            {
                StaticVars.MainWindow.addHostButton.IsEnabled = false;
                StaticVars.MainWindow.addHubButton.IsEnabled = false;
                StaticVars.MainWindow.addSwitchButton.IsEnabled = false;
                if (_hasMoved && _tmp && !_isInitialpositioning)
                {
                    Simulation.UndoStack.Push(new HistoryElement());
                    Simulation.RedoStack.Clear();
                    _tmp = false;
                }
                if ((Mouse.LeftButton == MouseButtonState.Released && !_isInitialpositioning) ||
                    (Mouse.LeftButton == MouseButtonState.Pressed && _isInitialpositioning))
                {
                    _isInitialpositioning = false;
                    _isMoving = false;
                    _tmp = true;
                    StaticVars.MainWindow.addHostButton.IsEnabled = true;
                    StaticVars.MainWindow.addHubButton.IsEnabled = true;
                    StaticVars.MainWindow.addSwitchButton.IsEnabled = true;
                }
                else if (Mouse.DirectlyOver != null)
                {
                    Position = Mouse.GetPosition(StaticVars.MainWindow.customCanvas);
                    _hasMoved = true;

                }
            }
            else
            {
                StaticVars.MainWindow.addHostButton.IsEnabled = true;
                StaticVars.MainWindow.addHubButton.IsEnabled = true;
                StaticVars.MainWindow.addSwitchButton.IsEnabled = true;
                _hasMoved = false;
                StaticVars.MainWindow.scrollViewer.MouseMove -= new MouseEventHandler(updatePosition);
            }
        }        

        public DeviceControl(SerializationInfo info, StreamingContext context)
        {
            InitializeComponent();
            GUID = (Guid) info.GetValue("GUID", typeof (Guid));
            switchTable = new SwitchTable();
            NetworkInterface1 = (NetworkInterface) info.GetValue("networkInterface1", typeof (NetworkInterface));
            NetworkInterface2 = (NetworkInterface) info.GetValue("networkInterface2", typeof (NetworkInterface));
            NetworkInterface3 = (NetworkInterface) info.GetValue("networkInterface3", typeof (NetworkInterface));
            NetworkInterface4 = (NetworkInterface) info.GetValue("networkInterface4", typeof (NetworkInterface));
            NetworkInterface5 = (NetworkInterface) info.GetValue("networkInterface5", typeof (NetworkInterface));
            NetworkInterface6 = (NetworkInterface) info.GetValue("networkInterface6", typeof (NetworkInterface));
            NetworkInterface7 = (NetworkInterface) info.GetValue("networkInterface7", typeof (NetworkInterface));
            NetworkInterface8 = (NetworkInterface) info.GetValue("networkInterface8", typeof (NetworkInterface));

            NetworkInterface1.IsEnabled = NetworkInterface1.IsEnabled;
            NetworkInterface2.IsEnabled = NetworkInterface2.IsEnabled;
            NetworkInterface3.IsEnabled = NetworkInterface3.IsEnabled;
            NetworkInterface4.IsEnabled = NetworkInterface4.IsEnabled;
            NetworkInterface5.IsEnabled = NetworkInterface5.IsEnabled;
            NetworkInterface6.IsEnabled = NetworkInterface6.IsEnabled;
            NetworkInterface7.IsEnabled = NetworkInterface7.IsEnabled;
            NetworkInterface8.IsEnabled = NetworkInterface8.IsEnabled;

            NetworkInterface1.Name = NetworkInterface1.Name;
            NetworkInterface2.Name = NetworkInterface2.Name;
            NetworkInterface3.Name = NetworkInterface3.Name;
            NetworkInterface4.Name = NetworkInterface4.Name;
            NetworkInterface5.Name = NetworkInterface5.Name;
            NetworkInterface6.Name = NetworkInterface6.Name;
            NetworkInterface7.Name = NetworkInterface7.Name;
            NetworkInterface8.Name = NetworkInterface8.Name;
            
            interfaces.Add(NetworkInterface1);
            interfaces.Add(NetworkInterface2);
            interfaces.Add(NetworkInterface3);
            interfaces.Add(NetworkInterface4);
            interfaces.Add(NetworkInterface5);
            interfaces.Add(NetworkInterface6);
            interfaces.Add(NetworkInterface7);
            interfaces.Add(NetworkInterface8);

            deviceLabel.Content = info.GetValue("label", typeof (string));

            Position = (Point) info.GetValue("position", typeof (Point));
            _initialDraggingPosition = (Point) info.GetValue("initialDraggingPosition", typeof (Point));
            _isInitialpositioning = false;
            _isMoving = false;
            RawImageData = (byte[]) info.GetValue("icon", typeof (byte[]));

            var stream = new MemoryStream(RawImageData);
            var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource bitmapSource = decoder.Frames[0];
            icon.Source = bitmapSource;
        }

        public Point Position
        {
            get { return new Point(Canvas.GetLeft(this), Canvas.GetTop(this)); }
            set
            {
                if (!Simulation.isRunning)
                {
                    Canvas.SetLeft(this, value.X - _initialDraggingPosition.X);
                    Canvas.SetTop(this, value.Y - _initialDraggingPosition.Y);
                    Opacity = 1;
                    try
                    {
                        if (NetworkInterface1.wireEnd != null && NetworkInterface1.wireEnd.wire!=null)
                            NetworkInterface1.wireEnd.wire.updateWire();
                        if (NetworkInterface2.wireEnd != null && NetworkInterface2.wireEnd.wire != null)
                            NetworkInterface2.wireEnd.wire.updateWire();
                        if (NetworkInterface3.wireEnd != null && NetworkInterface3.wireEnd.wire != null)
                            NetworkInterface3.wireEnd.wire.updateWire();
                        if (NetworkInterface4.wireEnd != null && NetworkInterface4.wireEnd.wire != null)
                            NetworkInterface4.wireEnd.wire.updateWire();
                        if (NetworkInterface5.wireEnd != null && NetworkInterface5.wireEnd.wire != null)
                            NetworkInterface5.wireEnd.wire.updateWire();
                        if (NetworkInterface6.wireEnd != null && NetworkInterface6.wireEnd.wire != null)
                            NetworkInterface6.wireEnd.wire.updateWire();
                        if (NetworkInterface7.wireEnd != null && NetworkInterface7.wireEnd.wire != null)
                            NetworkInterface7.wireEnd.wire.updateWire();
                        if (NetworkInterface8.wireEnd != null && NetworkInterface8.wireEnd.wire != null)
                            NetworkInterface8.wireEnd.wire.updateWire();
                    }
                    catch { }
                }
            }
        }

        protected NetworkInterface NetworkInterface1
        {
            get { return _networkInterface1; }
            set
            {
                value.Handler = networkInterface1Handler; ;
                networkInterface1Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface1Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface1Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface1 = value;
            }
        }

        protected NetworkInterface NetworkInterface2
        {
            get { return _networkInterface2; }
            set
            {
                value.Handler = networkInterface2Handler; ;
                networkInterface2Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface2Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface2Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface2 = value;
            }
        }

        protected NetworkInterface NetworkInterface3
        {
            get { return _networkInterface3; }
            set
            {
                value.Handler = networkInterface3Handler; ;
                networkInterface3Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface3Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface3Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface3 = value;
            }
        }

        protected NetworkInterface NetworkInterface4
        {
            get { return _networkInterface4; }
            set
            {
                value.Handler = networkInterface4Handler; ;
                networkInterface4Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface4Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface4Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface4 = value;
            }
        }

        protected NetworkInterface NetworkInterface5
        {
            get { return _networkInterface5; }
            set
            {
                value.Handler = networkInterface5Handler; ;
                networkInterface5Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface5Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface5Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface5 = value;
            }
        }

        protected NetworkInterface NetworkInterface6
        {
            get { return _networkInterface6; }
            set
            {
                value.Handler = networkInterface6Handler; ;
                networkInterface6Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface6Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface6Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface6 = value;
            }
        }

        protected NetworkInterface NetworkInterface7
        {
            get { return _networkInterface7; }
            set
            {
                value.Handler = networkInterface7Handler; ;
                networkInterface7Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface7Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface7Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface7 = value;
            }
        }

        protected NetworkInterface NetworkInterface8
        {
            get { return _networkInterface8; }
            set
            {
                value.Handler = networkInterface8Handler; ;
                networkInterface8Handler.MouseLeftButtonDown += value.UserControlMouseLeftButtonDown;
                networkInterface8Handler.MouseEnter += value.UserControlMouseEnter;
                networkInterface8Handler.MouseLeave += value.UserControlMouseLeave;
                value.Owner = this;
                _networkInterface8 = value;
            }
        }

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("GUID", GUID);
            info.AddValue("networkInterface1", NetworkInterface1);
            info.AddValue("networkInterface2", NetworkInterface2);
            info.AddValue("networkInterface3", NetworkInterface3);
            info.AddValue("networkInterface4", NetworkInterface4);
            info.AddValue("networkInterface5", NetworkInterface5);
            info.AddValue("networkInterface6", NetworkInterface6);
            info.AddValue("networkInterface7", NetworkInterface7);
            info.AddValue("networkInterface8", NetworkInterface8);

            info.AddValue("label", deviceLabel.Content);
            info.AddValue("position", Position);
            info.AddValue("initialDraggingPosition", _initialDraggingPosition);


            info.AddValue("icon", RawImageData);
        }

        #endregion

        private void IconMouseDown(object sender, MouseEventArgs e)
        {
            if (!_isMoving)
            {
                StaticVars.MainWindow.customCanvas.Children.Remove(this);
                StaticVars.MainWindow.customCanvas.Children.Add(this);
                _initialDraggingPosition = Mouse.GetPosition(this);
                _isMoving = true;
                StaticVars.MainWindow.scrollViewer.MouseMove += new MouseEventHandler(updatePosition);
                StaticVars.MainWindow.addHostButton.IsEnabled = false;
                StaticVars.MainWindow.addHubButton.IsEnabled = false;
                StaticVars.MainWindow.addSwitchButton.IsEnabled = false;
            }
            else
            {
                _isInitialpositioning = false;
                _isMoving = false;
                StaticVars.MainWindow.scrollViewer.MouseMove -= new MouseEventHandler(updatePosition);
                StaticVars.MainWindow.addHostButton.IsEnabled = true;
                StaticVars.MainWindow.addHubButton.IsEnabled = true;
                StaticVars.MainWindow.addSwitchButton.IsEnabled = true;
            }
        }

        private void DeviceControlContextMenuDeleteClick(object sender, RoutedEventArgs e)
        {
            delete();
        }

        public void delete()
        {
            if (MessageBox.Show("Usunąć " + deviceLabel.Content.ToString() + "?", "Potwierdzenie", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                foreach (NetworkInterface it in interfaces)
                {
                    if (it.wireEnd != null)
                        it.wireEnd.wire.DeleteWire();
                }
                StaticVars.MainWindow.customCanvas.Children.Remove(this);

            }
        }

        private void IconMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isInitialpositioning = false;
            _isMoving = false;
        }

        public void SetDeviceLabel(string devLabel)
        {
            deviceLabel.Content = devLabel;
        }

        public string GetDeviceLabel()
        {
            return (string) deviceLabel.Content;
        }

        protected abstract void DeviceControlContextMenuPropertiesClick(object sender, RoutedEventArgs e);
        

        private void UserControlMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (Mouse.DirectlyOver.GetType() != typeof (NetworkInterface))
            {
                foreach (UIElement it in StaticVars.MainWindow.customCanvas.Children)
                {
                    if (it.GetType().BaseType == typeof (DeviceControl))
                    {
                        ((DeviceControl) it).Deselect();
                    }
                }
                Select();
            }
            if (e.ClickCount == 2)
            {
                DeviceControlContextMenuPropertiesClick(sender, e);
            }
        }

        public void Select()
        {
            InfoBar.deviceControl = this;
            selectionBox.Visibility = Visibility.Visible;
            selectionBox.IsEnabled = false;
            _selected = true;
        }

        public void Deselect()
        {
            selectionBox.Visibility = Visibility.Hidden;
            selectionBox.IsEnabled = true;
            _selected = false;
        }

        public bool IsSelected()
        {
            return _selected;
        }

        private void UserControlLoaded(object sender, RoutedEventArgs e)
        {
            selectionBox.IsEnabled = false;
            selectionBox.Visibility = Visibility.Hidden;
            hoverBox.Visibility = Visibility.Hidden;
        }

        private void UserControlMouseEnter(object sender, MouseEventArgs e)
        {
            hoverBox.Visibility = !_isMoving ? Visibility.Visible : Visibility.Hidden;
            if (StaticVars.MainWindow.mainMenu_ShowDeviceStatus.IsChecked)
                StaticVars.MainWindow.statusLabel.ShowMessage(deviceLabel.Content + " [GUID:" + GUID.ToString() + "]");
        }

        private void UserControlMouseLeave(object sender, MouseEventArgs e)
        {
            hoverBox.Visibility = Visibility.Hidden;
            if (StaticVars.MainWindow.mainMenu_ShowDeviceStatus.IsChecked)
                StaticVars.MainWindow.statusLabel.FadeOut();
        }

        

        public abstract void sendFrame(Ethernet frameData);

        internal abstract void startReceiving(Signal signal, NetworkInterface networkInterface);

        internal abstract void stopReceiving(Signal signal, NetworkInterface networkInterface);

        internal abstract void abortReceiving(Signal signal, NetworkInterface networkInterface);

        internal abstract void reset();

        private void DeviceControlContextMenuShowReceivedClick(object sender, RoutedEventArgs e)
        {
            (new ShowReceived(receivedData, deviceLabel.Content.ToString())).Show();
        }
    }
}